import pika
import json
from typing import Dict, Any
from 新版2.系统组件.基础配置 import settings


class RabbitMQTickPublisher:
    """
    简单的RabbitMQ Tick数据发布者
    用于将实时Tick数据发送到消息队列
    """

    def __init__(self,
                 host: str = settings.RABBITMQ_HOST,
                 port: int = settings.RABBITMQ_PORT,
                 username: str = settings.RABBITMQ_USERNAME,
                 password: str = settings.RABBITMQ_PASSWORD,
                 exchange: str = 'tick_exchange',
                 queue: str = 'tick_queue'):
        """
        初始化发布者

        参数:
        - host: RabbitMQ服务器地址
        - port: RabbitMQ端口
        - username: 用户名
        - password: 密码
        - exchange: 交换机名称
        - queue: 队列名称
        """
        self.connection_params = pika.ConnectionParameters(
            host=host,
            port=port,
            credentials=pika.PlainCredentials(username, password)
        )
        self.exchange = exchange
        self.queue = queue
        self._setup_connection()

    def _setup_connection(self):
        """建立连接和通道"""
        self.connection = pika.BlockingConnection(self.connection_params)
        self.channel = self.connection.channel()

        # 声明交换机和队列
        self.channel.exchange_declare(exchange=self.exchange, exchange_type='direct')
        self.channel.queue_declare(queue=self.queue, durable=True)
        self.channel.queue_bind(exchange=self.exchange, queue=self.queue)

    def publish_order(self,order_data: Dict[str, Any]):
        """
        发布Tick数据到队列

        参数:
        - tick_data: Tick数据字典
        """
        try:
            # 如果连接已关闭则重新连接
            if self.connection.is_closed:
                self._setup_connection()
            print(f"消息发送{order_data}")

            self.channel.basic_publish(
                exchange=self.exchange,
                routing_key=self.queue,
                body=json.dumps(order_data),
                properties=pika.BasicProperties(
                    delivery_mode=2,  # 使消息持久化
                )
            )
        except Exception as e:
            print(f"Error publishing tick: {e}")
            # 尝试重新连接
            self._setup_connection()
            self.publish_order(order_data)  # 重试一次

    def close(self):
        """关闭连接"""
        if hasattr(self, 'connection') and self.connection.is_open:
            self.connection.close()


class RabbitMQTickSubscriber:
    """
    简单的RabbitMQ Tick数据订阅者
    用于从消息队列接收实时Tick数据
    """

    def __init__(self,
                 callback: callable,
                 host: str = settings.RABBITMQ_HOST,
                 port: int = settings.RABBITMQ_PORT,
                 username: str = settings.RABBITMQ_USERNAME,
                 password: str = settings.RABBITMQ_PASSWORD,
                 exchange: str = 'tick_exchange',
                 queue: str = 'tick_queue'):
        """
        初始化订阅者

        参数:
        - callback: 处理消息的回调函数
        - host: RabbitMQ服务器地址
        - port: RabbitMQ端口
        - username: 用户名
        - password: 密码
        - exchange: 交换机名称
        - queue: 队列名称
        """
        self.callback = callback
        self.connection_params = pika.ConnectionParameters(
            host=host,
            port=port,
            credentials=pika.PlainCredentials(username, password)
        )
        self.exchange = exchange
        self.queue = queue
        self._setup_connection()

    def _setup_connection(self):
        """建立连接和通道"""
        self.connection = pika.BlockingConnection(self.connection_params)
        self.channel = self.connection.channel()

        # 声明交换机和队列
        self.channel.exchange_declare(exchange=self.exchange, exchange_type='direct')
        self.channel.queue_declare(queue=self.queue, durable=True)
        self.channel.queue_bind(exchange=self.exchange, queue=self.queue)

        # 设置公平分发
        self.channel.basic_qos(prefetch_count=1)

    def _on_message(self, ch, method, properties, body):
        """消息处理包装器"""
        try:
            self.callback(ch, method, properties, body)
            ch.basic_ack(delivery_tag=method.delivery_tag)
        except Exception as e:
            print(f"Error processing message: {e}")
            ch.basic_nack(delivery_tag=method.delivery_tag, requeue=False)

    def start_consuming(self):
        """开始消费消息"""
        try:
            self.channel.basic_consume(
                queue=self.queue,
                on_message_callback=self._on_message,
                auto_ack=False
            )
            print(" [*] Waiting for ticks. To exit press CTRL+C")
            self.channel.start_consuming()
        except Exception as e:
            print(f"Error in consuming: {e}")
            self._setup_connection()
            self.start_consuming()

    def close(self):
        """关闭连接"""
        if hasattr(self, 'connection') and self.connection.is_open:
            self.connection.close()


# 使用示例
if __name__ == "__main__":
    # 发布者示例
    publisher = RabbitMQTickPublisher()
    test_ticks = [
        {"code": "600000", "price": 12.34, "volume": 1000, "time": "09:30:00"},
        {"code": "600000", "price": 12.35, "volume": 2000, "time": "09:30:01"},
        {"code": "000001", "price": 15.20, "volume": 1500, "time": "09:30:00"}
    ]

    for tick in test_ticks:
        publisher.publish_tick(tick_data=tick)
        print(f" [x] Sent tick: {tick}")

    publisher.close()


    # 订阅者示例
    def process_tick(ch, method, properties, body):
        tick = json.loads(body)
        print(f" [x] Received tick: {tick}")


    print("\nStarting subscriber...")
    subscriber = RabbitMQTickSubscriber(process_tick)
    try:
        subscriber.start_consuming()
    except KeyboardInterrupt:
        subscriber.close()
        print("Subscriber stopped")